package com.pig4cloud.pig.ads.gdt.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pig.ads.gdt.service.GdtAccesstokenService;
import com.pig4cloud.pig.ads.gdt.service.GdtCampaignDayReportService;
import com.pig4cloud.pig.ads.gdt.service.IGdtCampaignService;
import com.pig4cloud.pig.ads.pig.mapper.PlatformJobInfoMapper;
import com.pig4cloud.pig.ads.service.AdvService;
import com.pig4cloud.pig.ads.utils.CronUtils;
import com.pig4cloud.pig.ads.utils.OEHttpUtils;
import com.pig4cloud.pig.common.core.constant.enums.PlatformTypeEnum;
import com.pig4cloud.pig.common.core.util.DateUtil;
import com.pig4cloud.pig.api.dto.BudgetDto;
import com.pig4cloud.pig.api.entity.PlatformJobInfo;
import com.pig4cloud.pig.api.entity.ResponseBean;
import com.pig4cloud.pig.api.enums.StatusEnum;
import com.pig4cloud.pig.api.gdt.entity.GdtCampaign;
import com.pig4cloud.pig.api.gdt.entity.GdtCampaignDayReport;
import com.pig4cloud.pig.api.gdt.vo.GdtCampaignVo;
import com.pig4cloud.pig.ads.clickhouse3399.mapper.GdtCampaignDayReportMapper;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.security.util.SecurityUtils;
import com.pig4cloud.pig.api.util.MapUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

import org.apache.commons.lang3.StringUtils;

/**
 * @projectName:pig
 * @description:
 * @author:yk
 * @createTime:2020/12/16
 * @version:1.0
 */
@Log4j2
@Service
public class GdtCampaignDayReportServiceImpl extends ServiceImpl<GdtCampaignDayReportMapper, GdtCampaign> implements GdtCampaignDayReportService {

	@Autowired
	private GdtCampaignDayReportMapper campaignDayReportMapper;

	@Autowired
	private AdvService advService;

	@Autowired
	private PlatformJobInfoMapper platformJobInfoMapper;

	@Resource
	private IGdtCampaignService gdtCampaignService;
	@Resource
	private GdtAccesstokenService gdtAccesstokenService;

	@Value(value = "${gdt_url}")
	private String gdtUrl;

	@Value(value = "${gdt_campaigns_update_url}")
	private String gdtCampaignUpdateUrl;
	//private String gdtCampaignUpdateUrl = campaigns/update

	/**
	 * 根据clickhouse数据分析推广计划数据并重新设置
	 *
	 * @return
	 */
	@Override
	public R getCampaignDayReport(GdtCampaignVo req) {
		//设置分页条件
		Page page = new Page();
		page.setSize(req.getSize());
		page.setCurrent(req.getCurrent());
		//获取当前账号下 广点通广告账户列表
		List<String> accountList = advService.getOwnerAdv(SecurityUtils.getUser().getId(), PlatformTypeEnum.GDT.getValue());
		if (null == accountList || accountList.size() <= 0) {
			return R.ok(page);
		}
		//设置参数:广告账户ids集合
		//前端没传广告账户参数，通过当前账户查询
		String[] accountIds = req.getAccountIds();
		if (null == accountIds || accountIds.length <= 0) {
			req.setAccountList(accountList);
		} else {//前端有传广告账户参数
			List<String> accountIdsList = Arrays.asList(accountIds);
			req.setAccountList(accountIdsList);
		}
		//处理时间参数
		String sdate = req.getSdate();
		String edate = req.getEdate();
		if (StringUtils.isBlank(sdate) || StringUtils.isBlank(edate)) {
			req.setSdate(DateUtil.dateToString(new Date(), "yyyy-MM-dd"));
			req.setEdate(DateUtil.dateToString(new Date(), "yyyy-MM-dd"));
		}
		//广点通报表
		IPage<GdtCampaignDayReport> result = null;
		result = campaignDayReportMapper.selectGdtCampaignDayReport(req);
		// 根据拉取的数值 进行点击计算
		List<GdtCampaignDayReport> list = result.getRecords();
		if (CollectionUtils.isNotEmpty(list)) {
			for (int i = 0; i < list.size(); i++) {
				GdtCampaignDayReport gdtCampaignDayReport = list.get(i);
				Long campaignId = gdtCampaignDayReport.getCampaignId();
				GdtCampaign gdtCampaign = gdtCampaignService.getOne(Wrappers.<GdtCampaign>query().lambda()
						.eq(GdtCampaign::getCampaignId, campaignId).last("limit 0"));
				if (Objects.nonNull(gdtCampaign)) {
					//将mysql的开关状态设置到列表记录中
					BigDecimal dailyBudget = gdtCampaign.getDailyBudget().divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
					gdtCampaignDayReport.setConfiguredStatus(gdtCampaign.getConfiguredStatus());
					gdtCampaignDayReport.setCampaignName(gdtCampaign.getCampaignName());
					gdtCampaignDayReport.setDailyBudget(dailyBudget);
				}
			}
		}
		result.setRecords(list);
		return R.ok(result, "查询成功");
	}

	@Override
	public R updateOnOff(GdtCampaignVo req) {
		String configuredStatus = req.getConfiguredStatus();
		if (null == configuredStatus) {
			return R.failed("推广计划开关不允许为空");
		}
		if (!(configuredStatus.equals("AD_STATUS_NORMAL") || configuredStatus.equals("AD_STATUS_SUSPEND"))) {
			return R.failed("推广计划开关输入不合法：请输入\"AD_STATUS_NORMAL\"或者\"AD_STATUS_SUSPEND\"");
		}
		//获取主键
		Long campaignId = req.getCampaignId();
		String campaignIdStr = String.valueOf(campaignId);
		if (null == campaignId) {
			return R.failed("推广计划id不允许为空");
		}
		GdtCampaign campaign = gdtCampaignService.getById(campaignId);
		if (Objects.isNull(campaign)) {
			return R.failed("无此推广计划");
		}
		Long accountId = campaign.getAccountId();
		String accountIdStr = String.valueOf(accountId);
		Map<String, String> map = gdtAccesstokenService.fetchAccesstoken(accountIdStr);
		if (null == map || StringUtils.isEmpty(map.get("access_token"))) {
			return R.failed("广点通账户授权失败，请重试！");
		}
		String urlstr = gdtUrl + gdtCampaignUpdateUrl + "?" + MapUtils.queryString(map);
		log.info("修改广点通推广计划开关： request:" + urlstr);
		Map<String, Object> params = new HashMap<>();
		params.put("account_id", accountId);
		params.put("campaign_id", campaignId);
		params.put("configured_status", configuredStatus);
		//提交请求广点通修改推广计划接口
		String resultStr = OEHttpUtils.doPost(urlstr, params);
		log.info("修改广点通推广计划开关： response:" + resultStr);
		ResponseBean resBean = JSON.parseObject(resultStr, ResponseBean.class);
		String camId = null;
		if (resBean != null && "0".equals(resBean.getCode())) {
			//同步修改数据库
			JSONObject jsonObj = resBean.getData();
			camId = jsonObj.getString("campaign_id");
		}
		if (StringUtils.isBlank(camId)) {
			return R.failed("获取推广计划id失败");
		}

		if (!campaignIdStr.equals(camId)) {
			return R.failed("投放平台与广点通推广计划id不匹配");
		}
		int i = gdtCampaignService.update(req);
		return R.ok(i, "推广计划开关修改成功");
	}

	@Override
	public R updateDailyBudget(GdtCampaignVo req) {
		BigDecimal dailyBudget = req.getDailyBudget();
		if (null == dailyBudget || dailyBudget.compareTo(BigDecimal.ZERO) == -1) {
			return R.failed("未提供预算，或预算小于0");
		}
		if (dailyBudget.compareTo(BigDecimal.ZERO) == 1) {
			if (dailyBudget.compareTo(new BigDecimal("50")) == -1 || dailyBudget.compareTo(new BigDecimal("4000000")) == 1) {
				return R.failed("输入范围50-40,000,000元/天，修改幅度≥ 50元，下调日预算时：新预算≥当前推广计划日消耗+50元；若推广计划下包含朋友圈广告，新预算还需≥当前推广计划日消耗*1.5倍");
			}
		}
		Long campaignId = req.getCampaignId();
		String campaignIdStr = String.valueOf(campaignId);
		if (null == campaignId) {
			return R.failed("推广计划id不允许为空");
		}
		GdtCampaign campaign = gdtCampaignService.getById(campaignId);
		if (Objects.isNull(campaign)) {
			return R.failed("无此推广计划");
		}
		Long accountId = campaign.getAccountId();
		String accountIdStr = String.valueOf(accountId);
		Map<String, String> map = gdtAccesstokenService.fetchAccesstoken(accountIdStr);
		if (map == null || StringUtils.isEmpty(map.get("access_token"))) {
			return R.failed("广点通账户授权失败，请重试！");
		}
		String urlstr = gdtUrl + gdtCampaignUpdateUrl + "?" + MapUtils.queryString(map);
		log.info("修改广点通推广计划日预算： request:" + urlstr);
		int budget = dailyBudget.multiply(new BigDecimal("100")).intValue();
		Map<String, Object> params = new HashMap<>();
		params.put("account_id", accountId);
		params.put("campaign_id", campaignId);
		params.put("daily_budget", budget);
		//提交请求广点通修改广告组接口
		String resultStr = OEHttpUtils.doPost(urlstr, params);
		//结果为null，当做失败
		if (StringUtils.isBlank(resultStr)) {
			return R.failed("第三方更新失败:resultStr is null");
		}
		JSONObject obj = JSON.parseObject(resultStr);
		String code = obj.getString("code");
		if (!StringUtils.equals(code, "0")) {
			//String message = obj.getString("message_cn");
			//return R.failed("update bidAmount exception:" + message.replaceAll("(\\ )+\\w+", ""));
			return R.failed("输入范围50-40,000,000元/天，修改幅度≥ 50元，下调日预算时：新预算≥当前推广计划日消耗+50元；若推广计划下包含朋友圈广告，新预算还需≥当前推广计划日消耗*1.5倍");
		}
		log.info("修改广点通推广计划日预算： response:" + resultStr);
		ResponseBean resBean = JSON.parseObject(resultStr, ResponseBean.class);
		String camId = null;
		if (resBean != null && "0".equals(resBean.getCode())) {
			//同步修改数据库
			JSONObject jsonObj = resBean.getData();
			camId = jsonObj.getString("campaign_id");
		}
		if (StringUtils.isBlank(camId)) {
			return R.failed("获取推广计划id失败");
		}
		if (!campaignIdStr.equals(camId)) {
			return R.failed("投放平台与广点通推广计划id不匹配");
		}
		req.setDailyBudget(new BigDecimal(budget));
		int i = gdtCampaignService.update(req);
		return R.ok(i, "推广计划日预算修改成功");
	}

	@Override
	public R orderDailyBudget(BudgetDto budgetDto, Integer operate) {
		BigDecimal budget = budgetDto.getBudget();
		if (null == budget || budget.compareTo(BigDecimal.ZERO) == -1) {
			return R.failed("未提供预算，或预算小于0");
		}
		if (budget.compareTo(BigDecimal.ZERO) == 1) {
			if (budget.compareTo(new BigDecimal("50")) == -1 || budget.compareTo(new BigDecimal("4000000")) == 1) {
				return R.failed("输入范围50-40,000,000元/天，修改幅度≥ 50元，下调日预算时：新预算≥当前推广计划日消耗+50元；若推广计划下包含朋友圈广告，新预算还需≥当前推广计划日消耗*1.5倍");
			}
		}
		Long unionId = null;
		String jobName = null;
		//广告组 ==4
		unionId = budgetDto.getCampId();
		String adgIdStr = String.valueOf(unionId);
		if (null == unionId) {
			return R.failed("推广计划id不允许为空");
		}
		GdtCampaign campaign = gdtCampaignService.getById(unionId);
		if (Objects.isNull(campaign)) {
			return R.failed("无此推广计划");
		}

		jobName = "修改广点通推广计划预算";
		budgetDto.setAdvertiserId(campaign.getAccountId().toString());
		//添加日限额方式
		if (budget.compareTo(BigDecimal.ZERO) == 0) {
			budgetDto.setBudgetMode("BUDGET_MODE_INFINITE");
		} else {
			budgetDto.setBudgetMode("BUDGET_MODE_DAY");
		}
		budgetDto.setType(StatusEnum.TYPE_TWO.getStatus());
		//远程调用定时器项目创建定时任务
		try {
			//第二天凌晨执行
			Date exeTime = DateUtil.timeToBeginDay(DateUtil.getDate(new Date(), 1));
			String cronDate = CronUtils.getCron(exeTime);
			String exeParam = JSONObject.toJSONString(budgetDto);
			List<PlatformJobInfo> platformJobInfoList = platformJobInfoMapper.selectList(Wrappers.<PlatformJobInfo>query().lambda().eq(PlatformJobInfo::getUniqueId,unionId).eq(PlatformJobInfo::getOperateType,operate).eq(PlatformJobInfo::getType,StatusEnum.AD_TYPE_ONE.getStatus()).gt(PlatformJobInfo::getExecuteTime, new Date()));

			if (CollectionUtils.isEmpty(platformJobInfoList)) {
				//新增  -- 已经执行的以新增为标准，未执行以修改为准
				platformJobInfoMapper.insert(new PlatformJobInfo(unionId, jobName, cronDate, exeTime, exeParam, StatusEnum.JOB_STATUS_ONE.getStatus(), operate, StatusEnum.AD_TYPE_TWO.getStatus()));
			} else {
				//修改账号修改任务-----如果还没有执行
				platformJobInfoMapper.updateById(new PlatformJobInfo(unionId, exeParam, cronDate, exeTime, StatusEnum.JOB_STATUS_ONE.getStatus(), platformJobInfoList.get(0).getId()));
			}

		} catch (Exception e) {
			log.error("budgetUpdate  cron  is error:", e);
			return R.failed("定时修改日预算异常，请稍后重试");
		}
		return R.ok(budget, "定时修改日预算成功");
	}

	/**
	 * 查询广告组预约当天定时设置预算值
	 *
	 * @param
	 * @return
	 */
	@Override
	public R getAdvertiserJobBudget(BudgetDto budgetDto, Integer operateType) {
		Long unionId = null;
		unionId = budgetDto.getCampId();
		if (null == unionId) {
			return R.failed("推广计划id不允许为空");
		}
		GdtCampaign campaign = gdtCampaignService.getById(unionId);
		if (Objects.isNull(campaign)) {
			return R.failed("无此推广计划");
		}
		BigDecimal budget = null;
		List<PlatformJobInfo> platformJobInfoList = platformJobInfoMapper.selectList(Wrappers.<PlatformJobInfo>query().lambda().eq(PlatformJobInfo::getUniqueId,unionId).eq(PlatformJobInfo::getOperateType,operateType).eq(PlatformJobInfo::getType,StatusEnum.AD_TYPE_TWO.getStatus()).gt(PlatformJobInfo::getExecuteTime, new Date()));
		if (CollectionUtils.isNotEmpty(platformJobInfoList)) {
			String exParam = platformJobInfoList.get(0).getExecutorParam();
			BudgetDto dto = null;
			if (StringUtils.isNotBlank(exParam)) {
				dto = JSONObject.parseObject(exParam, BudgetDto.class);
				budget = dto.getBudget();
			}
		}
		return R.ok(budget, "获取次日日预算成功");
	}

}
